#include "copyright.h"
#include "dllist-driver.h"
#include "system.h"

extern int F;

//when F=xxx...xx1xb enable yield test
const int yieldLevel = 2;
//traversal the list from the first.
void traversal(DLList *testDLList)
{
    if (testDLList->IsEmpty())
    {
        printf("empty DLList.\n");
        return;
    }
    DLListElement *p = testDLList->Begin();
    printf("First's key:%d.\n", p->key);
    for (; p != NULL;
         p = p->next) // forward traversal
    {
        printf("%c", *((int *)p->item));
    }
    printf("\n");
    printf("backward traversal over.\n");
}
//reverse the traversal .
void retraversal(DLList *testDLList)
{
    if (testDLList->IsEmpty())
    {
        printf("empty DLList.\n");
        return;
    }
    DLListElement *p = testDLList->End();
    printf("Last's key:%d.\n", p->key);
    for (; p != NULL;
         p = p->forward) // backward traversal
    {
        printf("%c", *((int *)p->item));
    }
    printf("\n");
    printf("forward traversal over.\n");
}

void DLListDriver()
{
    /*test the DLList function*/
    char *str = "testDLList"; // "item" for the DLList
    DLList *testDLList = new DLList();
    // // let the test element be the first character 's', keyValue 5
    // DLListElement *testElement = new DLListElement(str, 5);

    // Append function
    testDLList->Append(str);
    // print the first element
    printf("First element: %c\n", *((int *)testDLList->Begin()->item));

    // Prepend function
    testDLList->Prepend(str + 1);
    printf("First element: %c\n", *((int *)testDLList->Begin()->item));

    // IsEmpty function
    if (testDLList->IsEmpty())
    {
        printf("testDLList Empty.\n");
    }
    else
    {
        printf("testDLList not Empty.\n");
    }

    // ~DLList function
    testDLList->~DLList();
    if (testDLList->IsEmpty())
    {
        printf("testDLList Empty.\n");
    }
    else
    {
        printf("testDLList not Empty.\n");
    }

    // SortedInsert function
    testDLList->SortedInsert(str, 0);
    testDLList->SortedInsert(str + 2, 2);
    testDLList->SortedInsert(str + 1, 1);
    printf("The first element is: %c\nThe last element is: %c\n",
           *((int *)testDLList->Begin()->item), *((int *)testDLList->End()->item));

    // DLList Traversal
    testDLList->~DLList();
    for (int i = 0; i < 10; ++i)
    {
        testDLList->SortedInsert(str + 10 - i - 1, i);
    }
    printf("backward traversal:\n");
    for (DLListElement *p = testDLList->Begin(); p != NULL;
         p = p->next) // forward traversal
    {
        printf("%c", *((int *)p->item));
    }
    printf("\n");
    printf("forward traversal:\n");
    for (DLListElement *p = testDLList->End(); p != NULL;
         p = p->forward) // backward traversal
    {
        printf("%c", *((int *)p->item));
    }
    printf("\n");
}

void GenerateRandomItemWithKeys(int N, DLList *list)
{
    // printf("[TEST]add %d random into list\n",N);
    for (int i = 0; i < N; i++)
    {
        int key = Random();
        int *item = new int;
        *item = key;

        MayBeYield(yieldLevel);

        list->SortedInsert(item, key);

        printf("%s:Insert key:%d finished\n", currentThread->getName(), key);
        MayBeYield(yieldLevel);
    }
}

void RemoveItemFromHead(int N, DLList *list)
{

    for (int i = 0; i < N; i++)
    {

        MayBeYield(yieldLevel);

        //printf("%s:", currentThread->getName());
        // if (list->IsEmpty())
        // {
        //     printf("%s:There is NO MORE ITEMS!\n", currentThread->getName());
        // }
        // else
        // {
        //     printf("%s:Remove item:%d finished.\n", currentThread->getName(), *((int *)list->Remove()));
        // }
        printf("%s:Remove item:%d finished.\n", currentThread->getName(), *((int *)list->Remove()));

        MayBeYield(yieldLevel);
    }
}

//----------------------------------------------------------------------
// MayBeYield
// 	test potential problem caused by concurrency
//----------------------------------------------------------------------
void MayBeYield(int flag)
{
    if ((F >> (flag - 1)) & 1)
    {
        if (Random() % 2 == 0)
        {
            // DEBUG('t', "Thread %s Yield\n", currentThread->getName());
            // printf("I:%s wanna go to yield.\n",currentThread->getName());
            currentThread->Yield();
        }
    }
}
